'use strict';

const Conf = require('conf');
const colors = require('colors');
const inquirer = require('inquirer');

const Command = require('@x3-cli-dev/command');
const log = require('@x3-cli-dev/log');
const { execCommandAsync, arrGroup, getServerSchema } = require('@x3-cli-dev/utils');
const CONF_SCHEMA = getServerSchema();

const SERVER_KEY = 'server';
const DEFAULT_SERVER = 'defaultServer';
class ConfigCommand extends Command {
  init() {
    this.set = this._options.set;
    this.get = this._options.get;
    this.delete = this._options.delete;
    this.list = !!this._options.list;
    this.edit = !!this._options.edit;
    this.listServer = !!this._options.listServer;
    this.addServer = this._options.addServer;
    this.useServer = this._options.useServer;
    this.removeServer = this._options.removeServer;
    this.optionKeys = Object.keys(this._options);
    log.verbose('options', this._options);
    log.verbose('optionKeys', this.optionKeys);
  }

  async exec() {
    await this.prepare();
    await this.changeConfig();
  }

  async prepare() {
    await this.checkConf();
  }

  async checkConf() {
    const cliPath = process.env.X3_CLI_HOME_PATH;
    const config = new Conf({
      cwd: cliPath,
    });
    log.verbose('config', config.get());
    this.confStore = config;
  }

  async changeConfig() {
    const fnMap = {
      set: this.setFn,
      get: this.getFn,
      edit: this.editFn,
      list: this.listFn,
      delete: this.deleteFn,
      listServer: this.listServerFn,
      addServer: this.addServerFn,
      useServer: this.useServerFn,
      removeServer: this.removeServerFn,
    };
    for (const key of this.optionKeys) {
      await fnMap[key].call(this);
    }
  }

  async setFn() {
    const group = arrGroup(this.set, 2);
    log.verbose('arrGroup', group);
    for (const [key, value] of group) {
      this.confStore.set(key, value ?? '');
      log.info(`${key}=${value ?? ''}`);
    }
  }

  async getFn() {
    for (const key of this.get) {
      if (this.confStore.has(key)) {
        const value = this.confStore.get(key);
        log.info(colors.green(`${key}=${value ?? ''}`));
      } else {
        log.info(colors.red(`not has ${colors.blue(key)} property`));
      }
    }
  }

  async deleteFn() {
    for (const key of this.delete) {
      if (this.confStore.has(key)) {
        this.confStore.delete(key);
        log.info(`key: ${key}`, colors.green('delete success'));
      } else {
        log.info(colors.red(`not has ${colors.blue(key)} property`));
      }
    }
  }

  async listFn() {
    console.log(colors.magenta('----------------------------config------------------------------'));
    console.log(JSON.stringify(this.confStore.get(), null, 2));
    console.log(colors.magenta('----------------------------------------------------------------'));
  }

  async editFn() {
    const configPath = this.confStore.path;
    await execCommandAsync(`vim ${configPath}`);
  }

  async listServerFn() {
    const serverObj = this.getServerConf();
    const defaultServer = this.confStore.get(DEFAULT_SERVER);
    if (Object.keys(serverObj).length && typeof defaultServer === 'string' && defaultServer) {
      if (serverObj.hasOwnProperty(defaultServer)) {
        const defaultName = `* ${defaultServer}`;
        serverObj[`${colors.blue(defaultName)}`] = serverObj[defaultServer];
        delete serverObj[defaultServer];
      }
    }
    console.table(serverObj);
    log.info(`默认服务器配置(defaultServer): ${colors.blue(defaultServer)}`);
  }

  async addServerFn() {
    const server = this.addServer;
    const serverObj = this.getServerConf();

    if (!serverObj.hasOwnProperty(server)) {
      const conf = await this.buildServerConf();
      log.verbose('serverConf', conf);

      serverObj[server] = conf;
      // 只存在一个配置时自动设置为默认 server
      if (Object.keys(serverObj).length === 1) {
        this.confStore.set(DEFAULT_SERVER, server);
      }
      this.confStore.set(SERVER_KEY, serverObj);
      log.info(`${server} 添加成功`);
      this.listServerFn();
    } else {
      this.listServerFn();
      throw new Error(`已存在 ${server} 配置`);
    }
  }

  async buildServerConf() {
    const needSet = CONF_SCHEMA;
    const confObj = await inquirer.prompt(
      needSet.map(item => ({
        name: item.key,
        message: item.message,
        type: item.type,
        default: item.default,
        validate: function (input) {
          const done = this.async();
          input ? done(null, true) : done(item.message);
        },
      })),
    );
    return confObj;
  }

  async useServerFn() {
    const server = this.useServer;
    const serverObj = this.getServerConf();
    if (serverObj.hasOwnProperty(server)) {
      this.confStore.set(DEFAULT_SERVER, server);
    } else {
      this.listServerFn();
      throw new Error(`找不到 ${colors.yellow(server)} 服务器配置`);
    }
    this.listServerFn();
    log.info(`${server} 设置默认服务器配置成功`);
  }

  async removeServerFn() {
    const server = this.removeServer;
    const serverObj = this.getServerConf();
    if (serverObj.hasOwnProperty(server)) {
      delete serverObj[server];
      this.confStore.set(SERVER_KEY, serverObj);
    }
    this.listServerFn();
    log.info(`删除 ${server} 成功`);
  }

  getServerConf() {
    return this.confStore.get()[SERVER_KEY] || {};
  }
}

function config(argv) {
  return new ConfigCommand(argv);
}

module.exports = config;
module.exports.ConfigCommand = ConfigCommand;
